/*
 * (C) Copyright 2014
 * David Feng <fenghua@phytium.com.cn>
 * Sharma Bhupesh <bhupesh.sharma@freescale.com>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */
#include <asm/arch/sprd_reg.h>
#include <asm/io.h>
#include <common.h>
#include <malloc.h>
#include <boot_mode.h>
#include <adi_hal_internal.h>
#include <chipram_env.h>
#include <sprd_adc.h>
#include <sprd_led.h>
#include <sprd_battery.h>
#include <linux/ctype.h>

DECLARE_GLOBAL_DATA_PTR;
phys_size_t real_ram_size = 0x40000000;

phys_size_t get_real_ram_size(void)
{
        return real_ram_size;
}

void enable_global_clocks(void)
{
	u32 val;

	sci_glb_set(REG_AON_APB_APB_EB0, BIT_AON_APB_GPU_EB |
		BIT_AON_APB_MM_EB);
	sci_glb_clr(REG_PMU_APB_PD_GPU_TOP_CFG, BIT_PMU_APB_PD_GPU_TOP_FORCE_SHUTDOWN);
	sci_glb_clr(REG_PMU_APB_PD_MM_TOP_CFG, BIT_PMU_APB_PD_MM_TOP_FORCE_SHUTDOWN);
	val = sci_glb_read(REG_PMU_APB_PWR_STATUS3_DBG);
	udelay(1000);
	while (val & BIT_PMU_APB_PD_MM_TOP_STATE(~0));
	sci_glb_set(REG_MM_AHB_AHB_EB, BIT_MM_AHB_CKG_EB);
}

extern void setup_chipram_env(void);
#define CMD_BUFFER_LEN	64
int cmd_buffer_cnt = 0;
char cmd_buffer[CMD_BUFFER_LEN];

struct gpio_addr{
  int gpio_num;
  uint32_t addr;
};

struct gpio_addr gpio_n[79] = {
{123,0x1A0},
{49,0x0058}, /**/
{48,0x0054},
{22,0x01C4},//Y
{23,0x01C8},//Y
{28,0x01DC},//Y
{30,0x01E4},//Y
{29,0x01E0},//Y
{131,0x0024},//
{89,0x024C},//
{8,0x01F8},//Y
{7,0x01F4},//Y
{132,0x0028},//
{133,0x002C},//
{9,0x01fc},  //Y
{160,0x0180},//
{161,0x0184},//
{162,0x0188},//
{31,0x01E8},//Y
{159,0x017c},//
{156,0x0170},//Y
{157,0x0174},//
{158,0x0178},//
{78,0x00A4},//Y
{144,0x0044},//Y
{145,0x0048},//Y
{146,0x004c},//Y
{147,0x0050},//Y
{50,0x00F4},//Y
{51,0x00F8},//Y
{44,0x0070},//Y
{46,0x0074},//Y
{43,0x0078},//Y
{45,0x007C},//Y
{47,0x0080},//Y
{74,0x005C},//Y
{75,0x0060},//
{125,0x01A8},//
{126,0x01AC},//Y
{60,0x0084},//Y
{61,0x0088},//Y
{62,0x008c},//Y
{63,0x0090},//Y
{71,0x0098},//
{70,0x0094},//
{72,0x009C},//
{73,0x00A0},//
{155,0x0190},//
{154,0x018C},//
{127,0x0030},//Y
{128,0x0034},//Y
{87,0x0244},//Y
{86,0x0240},//Y
{85,0x023c},//Y
{88,0x0248},//Y
{139,0x016c},//
{136,0x0160},//
{135,0x015c},//
{134,0x0158},//
{11,0x0204},//
{10,0x0200},//
{138,0x0168},//
{121,0x0198},//
{52,0x021C},//Y
{53,0x0220},//
{54,0x0224},//Y
{55,0x0228},//Y
{122,0x019C},//Y
{33,0x01F0},//
{130,0x0020},//
{93,0x0238},//Y
{90,0x022C},//Y
{91,0x0230},//Y
{92,0x0234},//Y
{32,0x01EC},//Y
{124,0x01A4},//
{129,0x0038},//
{24,0x01CC},/* NO PIN */
{26,0x01D4},/* NO PIN */
};

void gpio_test_mode(void){
	char ch;
	uint32_t gpio, enable, i ;
	int32_t adcI3,adcI3_Vol;
	int32_t adcI2,adcI2_Vol;
	int32_t adcI5,adcI5_Vol;
	cmd_buffer_cnt = 0;
	memset(cmd_buffer, 0, CMD_BUFFER_LEN);
	while(1)
	{
		ch = serial_getc();
		putc(ch);

		if(ch == 0x0a)
		{
			continue;
		}

		if(ch == 0x0d)
		{
			printf("CMD BUF %s.\n", cmd_buffer);

			if(memcmp(cmd_buffer, "GPIO,", 5)!=0 && memcmp(cmd_buffer, "ADC,", 4)!=0)
			{
				printf("%s: %d\n", __func__, __LINE__);
				goto error;
			}
			if(memcmp(cmd_buffer, "GPIO,", 5)==0)
			{
			gpio = 0;
			enable = 0;
			i = 5;

			while(isdigit(cmd_buffer[i]))
			{
				gpio *= 10;
				gpio += cmd_buffer[i] - '0';
				i++;
				printf(" the gpio val is = %d.\n", gpio);
			}

			if(gpio == 999)
			{
				break;
			}

			i++;
			while(isdigit(cmd_buffer[i]))
			{
				enable *= 10;
				enable += cmd_buffer[i] - '0';
				i++;
				printf(" the enable val is = %d.\n", enable);
			}

			//if(enable == 1)
			//{
			//	enable = 2;
			//}


			printf("gpio=%d,enable=%d.\n", gpio, enable);




   //   sprd_gpio_free(NULL,gpio);

      for(i=0;i<79;i++){
        if(gpio == gpio_n[i].gpio_num)
          writel(0x30,0x402a0000+gpio_n[i].addr);
      }
			sprd_gpio_request(NULL,gpio);
			sprd_gpio_direction_output(NULL,gpio,enable);
			//sprd_gpio_set(NULL,gpio,enable);
			if(enable ==0)
			{
				printf("gpio pull low\n");
			}
			else{
				printf("gpio pull up \n");
			}
			//dsb();

			cmd_buffer_cnt = 0;
			memset(cmd_buffer, 0, CMD_BUFFER_LEN);
			printf("OK\r\n");
			continue;
			}
			if(memcmp(cmd_buffer, "ADC,",4)==0)
			{
				if(cmd_buffer[4]=='1' && cmd_buffer[5]=='2' && cmd_buffer[6]=='8' )
				{
					if (-1 == pmic_adc_get_values(3, true, 1, &adcI3)) {
						printf("ADC128:FAIL\n");
					}
           adcI3_Vol=sprd_chan_small_adc_to_vol(3,true,1,adcI3);
				//	printf("ADC128:adc =%d ,vol=%d\n",adcI3,adcI3_Vol);
					if(adcI3_Vol>800 && adcI3_Vol<1000)
						 printf("ADC128:OK\n");
					else
					{
						printf("ADC128:FAIL\n");
					}
				}else if(cmd_buffer[4]=='1' && cmd_buffer[5]=='3' && cmd_buffer[6]=='3' ){
					if (-1 == pmic_adc_get_values(5, true, 1, &adcI5)) {
						printf("ADC133:FAIL\n");
					}
           adcI5_Vol=sprd_chan_small_adc_to_vol(5,true,1,adcI5);

          //adcI5_Vol = sprd_chan_bat_adc_to_vol()
					//printf("ADC133:adc =%d ,vol=%d\n",adcI5,adcI5_Vol);
					if(adcI5_Vol>3400 && adcI5_Vol<3800)
						 printf("ADC133:OK\n");
					else
					{
						printf("ADC133:FAIL\n");
					}
				}else if(cmd_buffer[4]=='1' && cmd_buffer[5]=='8' && cmd_buffer[6]=='5'){
					if (-1 == pmic_adc_get_values(2, true, 1, &adcI2)) {
						printf("ADC185:FAIL\n");
					}
           adcI2_Vol=sprd_chan_small_adc_to_vol(2,true,1,adcI2);
				//	printf("ADC185:adc =%d ,vol=%d\n",adcI2,adcI2_Vol);
					if(adcI2_Vol>1600 && adcI2_Vol<2000)
						 printf("ADC185:OK\n");
					else
					{
						printf("ADC185:FAIL\n");
					}

				}
				 cmd_buffer_cnt = 0;
           		 memset(cmd_buffer, 0, CMD_BUFFER_LEN);
				continue;
			}
error:
			printf("ERROR\r\n");
			cmd_buffer_cnt = 0;
			memset(cmd_buffer, 0, CMD_BUFFER_LEN);
		}
		else
		{
			cmd_buffer[cmd_buffer_cnt++] = ch;
			if(cmd_buffer_cnt == CMD_BUFFER_LEN)
			{
				cmd_buffer_cnt = 0;
			}
		}
	}
	return;
}
#define ANA_VIBRATOR_CTRL0_U      (ANA_REG_GLB_VIBR_CTRL0)

#define CUR_DRV_CAL_SEL_U	(0x0 << 12)
#ifdef CONFIG_ADIE_SC2730
	#define SLP_LDOVIBR_PD_EN_U		BIT_SLP_LDO_VDDVIB_PD_EN
	#define LDO_VIBR_PD_U			BIT_LDO_VDDVIB_PD
#else
	#define SLP_LDOVIBR_PD_EN_U	(0x1 << 9)
	#define LDO_VIBR_PD_U		(0x1 << 8)
#endif
#define LDO_VIBR_V_U		(0xB4)

int board_init(void)
{
	int i;
	char ch;
	setup_chipram_env();
#ifndef CONFIG_FPGA
	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
	ADI_init();
	/*FPGA forbiden*/
	//misc_init();
	regulator_init();
	regulator_enable("vddcamio");
	pmic_adc_Init();
	/*FPGA forbiden*/
	pin_init();
	sprd_gpio_init();
	misc_init();
	sprd_eic_init();
	sprd_led_init();
	/*FPGA forbiden*/
	sprd_pmu_lowpower_init();
	TDPllRefConfig(1);
	enable_global_clocks();
#endif
	printf("CTRL+C: enter instruction mode\n");
	for(i=100;i!=0;i--){
		if(serial_tstc() > 0){
		if(serial_getc()==0x03){
			printf("Please input your instruction:\n\n");
			printf("PINTEST: test gpio(s) connectivity.\n");
      sprd_gpio_request(NULL,89);
			sprd_gpio_direction_output(NULL,89,1);
			regulator_enable("vddcama");
			regulator_enable("vddcamio");
			regulator_enable("vddcamd");
			regulator_enable("vddcammot");
			regulator_enable("vddsim1");
			regulator_enable("vddsim0");
			regulator_enable("vddsdcore");
			regulator_enable("vddsdio");
  	  ANA_REG_MSK_OR(ANA_VIBRATOR_CTRL0_U,CUR_DRV_CAL_SEL_U,CUR_DRV_CAL_SEL_U);
	    ANA_REG_MSK_OR(ANA_VIBRATOR_CTRL0_U,LDO_VIBR_V_U,LDO_VIBR_V_U);
   		ANA_REG_AND(ANA_VIBRATOR_CTRL0_U, ~LDO_VIBR_PD_U);
  		ANA_REG_AND(ANA_VIBRATOR_CTRL0_U, ~SLP_LDOVIBR_PD_EN_U);
			while(1){
				ch = serial_getc();
				putc(ch);
				printf("get ch =%c\n",ch);
				if((ch >= 'A' && ch <= 'Z')
				 ||(ch >= 'a' && ch <= 'z')
				 || ch == 0x0d)
				{
					if(ch == 0x0d)
					{

						if(strlen("PINTEST") == cmd_buffer_cnt
							&& !memcmp(cmd_buffer, "PINTEST", cmd_buffer_cnt))
						{
							printf("PIN TEST MODE\r\n", __func__);
							gpio_test_mode();
							goto normal_boot;
						}
						else
						{
							printf("%s: invalid cmd %s.\n", __func__, cmd_buffer);
						}

						cmd_buffer_cnt = 0;
						memset(cmd_buffer, 0, CMD_BUFFER_LEN);
					}
					else
					{
						cmd_buffer[cmd_buffer_cnt++] = ch;
						if(cmd_buffer_cnt == CMD_BUFFER_LEN)
						{
							cmd_buffer_cnt = 0;
						}
					}
				}
				else
				{
					cmd_buffer_cnt = 0;
				}
			}
			}
			}
		mdelay(10);
	}
normal_boot:
	return 0;
}
int dram_init(void)
{
#ifdef CONFIG_DDR_AUTO_DETECT
	ulong sdram_base = CONFIG_SYS_SDRAM_BASE;
	ulong sdram_size = 0;
	chipram_env_t * env = CHIPRAM_ENV_LOCATION;
	if (CHIPRAM_ENV_MAGIC != env->magic) {
		printf("Chipram magic wrong , ddr data may be broken\n");
		return 0;
	}

	real_ram_size = 0;

	if (env->cs_number == 1) {
		real_ram_size += env->cs0_size;
	} else if(env->cs_number == 2){
		real_ram_size += env->cs0_size;
		real_ram_size += env->cs1_size;
	}

	//real_ram_size = get_ram_size((volatile void *)sdram_base, real_ram_size);
#else
	real_ram_size = REAL_SDRAM_SIZE;
#endif

        gd->ram_size = PHYS_SDRAM_1_SIZE;

        return 0;
}

#ifdef CONFIG_DUAL_DDR
void dram_init_banksize(void)
{
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
	gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
	gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
}
#endif


int misc_init_r(void)
{
	/*reserver for future use*/
	return 0;
}

static void battery_init(void)
{
	sprdchg_common_cfg();
	sprdchg_fan54015_init();
	sprdbat_init();
}

int board_late_init(void)
{

 boot_mode_t boot_role;
        extern chipram_env_t* get_chipram_env(void);
        chipram_env_t* cr_env = get_chipram_env();
        boot_role = cr_env->mode;

	boot_pwr_check();

#if !defined(CONFIG_FPGA)
#ifdef CONFIG_NAND_BOOT
	//extern int nand_ubi_dev_init(void);
	nand_ubi_dev_init();
	debugf("nand ubi init OK!\n");
#endif
	battery_init();
	debugf("CHG init OK!\n");
#endif
	board_keypad_init();

	return 0;
}


CBOOT_FUNC s_boot_func_array[CHECK_BOOTMODE_FUN_NUM] = {
	get_mode_from_bat_low,
	write_sysdump_before_boot_extend,
	get_mode_from_miscdata_boot_flag,
	/* 1 get mode from file*/
	get_mode_from_file_extend,
	/* 2 get mode from watch dog*/
	get_mode_from_watchdog,
	/*3 get mode from alarm register*/
	get_mode_from_alarm_register,
	/*0 get mode from calibration detect*/
	get_mode_from_pctool,
	/*4 get mode from charger*/
	get_mode_from_charger,
	/*5 get mode from keypad*/
	get_mode_from_keypad,
	/*6 get mode from gpio*/
	get_mode_from_gpio_extend,

	/*shutdown device*/
	//get_mode_from_shutdown,
	0
};



void board_boot_mode_regist(CBOOT_MODE_ENTRY *array)
{
	MODE_REGIST(CMD_NORMAL_MODE, normal_mode);
	MODE_REGIST(CMD_RECOVERY_MODE, recovery_mode);
	MODE_REGIST(CMD_FASTBOOT_MODE, fastboot_mode);
	MODE_REGIST(CMD_WATCHDOG_REBOOT, watchdog_mode);
	MODE_REGIST(CMD_AP_WATCHDOG_REBOOT, ap_watchdog_mode);
	MODE_REGIST(CMD_UNKNOW_REBOOT_MODE, unknow_reboot_mode);
	MODE_REGIST(CMD_PANIC_REBOOT, panic_reboot_mode);
	MODE_REGIST(CMD_AUTODLOADER_REBOOT, autodloader_mode);
	MODE_REGIST(CMD_SPECIAL_MODE, special_mode);
	MODE_REGIST(CMD_CHARGE_MODE, charge_mode);
	MODE_REGIST(CMD_ENGTEST_MODE,engtest_mode);
	MODE_REGIST(CMD_FACTORYTEST_MODE, factorytest_mode);
	MODE_REGIST(CMD_CALIBRATION_MODE, calibration_mode);
	MODE_REGIST(CMD_EXT_RSTN_REBOOT_MODE, normal_mode);
	MODE_REGIST(CMD_IQ_REBOOT_MODE, iq_mode);
	MODE_REGIST(CMD_ALARM_MODE, alarm_mode);
	MODE_REGIST(CMD_SPRDISK_MODE, sprdisk_mode);
	MODE_REGIST(CMD_AUTOTEST_MODE, autotest_mode);
	MODE_REGIST(CMD_APKMMI_MODE, apkmmi_mode);
	MODE_REGIST(CMD_UPT_MODE, upt_mode);
	return ;
}

